=begin rdoc
Determine Routing from a TOSSIM simulation file and write out detailed information

Author::    Matthias Woehrle  (mailto:matthias.woehrle@tik.ee.ethz.ch)
Copyright:: Copyright (c) 2008 ETH Zurich
License::   

TODO:

MISSING:

=end
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
sourcepath =  File.expand_path("/Users/matthias/Documents/ETH/tecdoc/woehrlem/paper/woehrlem2008_sensys_poster/trunk/src/tossim")


require "rupeas"


Rupeas.new do

Type :senddone do
 with :name =>:seqNo, :fieldtype=> :periodic, :range => 0..255, :notification => :error
 with :name =>:origin, :fieldtype => :integer, :range => 0..100,:notification => :error
 with :name =>:destination, :fieldtype => :integer, :range => 0..100, :notification => :warning
 with :name =>:nodeid,:fieldtype=> :integer, :range => 0..100,:notification => :error
 with :name =>:time, :fieldtype => :float, :notification => :warning 
end

Type :receive do
 with :name =>:seqNo, :fieldtype=> :periodic, :range => 0..255, :notification => :error
 with :name =>:origin, :fieldtype => :integer, :range => 0..100,:notification => :error
 with :name =>:destination, :fieldtype => :integer, :range => 0..100, :notification => :warning
 with :name =>:nodeid,:fieldtype=> :integer, :range => 0..100,:notification => :error
 with :name =>:time, :fieldtype => :float, :notification => :warning 
end

filename = 'minuscule.log'
t=Time.new
monthdayhourmin = t.strftime("%y-%m-%d--%H%M")
csvfile = File.open('result-' + filename + '-' + monthdayhourmin + '.csv', 'w')
csvfile.write("origin, arrived, arrived0, arrvied100, doubles, real doubles, unsuccessful, sent, unprocessed, hop_count, hop_count0, hop_count100\n")
pathfile = File.open('path-' + filename + '-' + monthdayhourmin + '.txt', 'w')
r = File.open('logfile-' + filename + '-' + monthdayhourmin + '.txt', 'w')


all = loadlog(sourcepath + '/' + filename)

total_metrics = origin_metrics = Hash.new
total_metrics.default = origin_metrics.default = 0



[10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,0,43,44,45,46,100,48,49,50,51,52,53,
  54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79].each do |origin|
#[29].each do |origin|

  origin_metrics.each_key {| key | origin_metrics[key]=0 }

  originfiltered = all_transmissions = EventSet.new

  if all[:origin=>origin].length > 0
     originfiltered = all[:origin=>origin]
     r.write "------------\nProcessing #{all[:origin=>origin].length} events for origin #{origin}\n------------\n"
     puts "------------\nProcessing #{originfiltered.length} events for origin #{origin}\n"
     
     
     
    all.values(:seqNo).each do |seqNo|
#     [67,68].each do |seqNo|
       
       #puts "------------\nProcessing #{originfiltered[:seqNo=>seqNo].length} events for origin #{origin} and sequence Number #{seqNo}\n"
       
       routestart_temp = originfiltered[:seqNo=>seqNo].predicate(1){|send| send[:origin] == send[:nodeid] and send[:type] == :senddone}
       routestart = set_transform(routestart_temp, :merge, 1) do |e1|
            {
              :type => :transmission,
              :nodeid => e1[:nodeid],
              :destination => e1[:destination],
              :seqNo => e1[:seqNo],
              :origin => e1[:origin],
              :time => e1[:time],
              :path => e1[:nodeid].to_s,
              :hop_count => 0.5
            }
            end
            
       packet_starts = routestart[:type=>:transmission].length
              
       resultset = routestart.iterative do |iteration|
          temp = iteration.predicate(2) {|e1, e2| e1[:origin] == e2[:origin]  and ((e1[:type] == :transmission and \
          e2[:type] == :receive and e1[:destination] == e2[:nodeid]) or (e1[:nodeid] == e2[:nodeid] and
          e1[:type] == :transmission and e2[:type] == :senddone))
          }
          iteration.set_transform(temp, :merge, 2) do |e1, e2|
          {
            :nodeid => e2[:nodeid],
            :type => :transmission,
            :origin => e1[:origin],
            :destination => e2[:destination],
            :seqNo => e1[:seqNo],
            :time => e2[:time],
            :path => (e1[:path].to_s + '-' + e2[:nodeid].to_s),
            :hop_count => e1[:hop_count] + 0.5
          }
         end
       end
       
       transmission = resultset[:type=>:transmission]
       transmissions_to_0 = transmission[:nodeid=>0]
       transmissions_to_100 = transmission[:nodeid=>100]
       all_transmissions = transmissions_to_0.union(transmissions_to_100)
       
       success0   =     transmissions_to_0.length
       success100 =     transmissions_to_100.length
       success = transmission.length
                                    
       unsuccesful_routing = success - success100 - success0
       origin_metrics[:unsuccesful] += unsuccesful_routing
       
       other_packets = resultset[:type=>:senddone].union(resultset[:type=>:receive])
       origin_metrics[:other_length] += other_packets.length
       
       r.write("Others" + other_packets.to_s + "\n") if other_packets.length > 0
              
       #We have actually sent packets
       if packet_starts > 0
         total_metrics[:sent] += 1
         origin_metrics[:sent] += 1
         origin_metrics[:success] += success
         origin_metrics[:success0] += success0
         origin_metrics[:success100] += success100
         
         if success == 0
           r.write("Unsuccessful and failed" + unsuccesful_routing.to_s + "\n") if unsuccesful_routing.length > 0
         else #success >0
           r.write("Unsuccessful, but recovered" + unsuccesful_routing.to_s + "\n") if unsuccesful_routing > 0
           transmissions_to_0.each   {|trans0_event|   origin_metrics[:hop_counts0]+= trans0_event[:hop_count]} 
           transmissions_to_100.each {|trans100_event| origin_metrics[:hop_counts100]+= trans100_event[:hop_count]}            
           total_metrics[100] += 1 if success100 > 0
           total_metrics[0] += 1 if success0 > 0
           total_metrics[:arrived] += 1
           origin_metrics[:arrived] += 1
           origin_metrics[100] += 1 if success100 > 0
           origin_metrics[0] += 1 if success0 > 0

           if success > 1
            origin_metrics[:duplicates] += success-1
            total_metrics[:duplicates] += success-1
            transmission.remove_key(:time)
            match = true
            ref_event = nil
            transmission.each do |event|
              ref_event || ref_event = event
              if event != ref_event
                match = true
                break
              end
            end
            if match == false
              origin_metrics[:real_duplicates] += 1
              total_metrics[:real_duplicates] += 1
              r.write("Duplicates" + transmission.to_s + "\n")
            else
             r.write("Fake duplicates" + transmission.to_s + "\n")             
            end
          end
          
         end
       else 
         r.write "\nGhost packet for #{origin}/#{seqNo}\n" if success > 0
       end

       end

     end

     all_transmissions.values(:path).each do |given_path|
       pathfile.write("#{all_transmissions[:path=>given_path].length.to_f / origin_metrics[:success]} for path #{given_path}\n")
    end

    
    origin_metrics[:hop_counts] = (origin_metrics[:hop_counts0] + origin_metrics[:hop_counts100])/(origin_metrics[:success0]+origin_metrics[:success100]) if (origin_metrics[:success0]+origin_metrics[:success100])>0
    origin_metrics[:hop_counts0] /= origin_metrics[:success0]  if origin_metrics[:success0] > 0
    origin_metrics[:hop_counts100] /= origin_metrics[:success100]  if origin_metrics[:success100] > 0
        
    csvfile.write(origin.to_s + ',' + origin_metrics[:arrived].to_s + ',' + origin_metrics[0].to_s + ',' + origin_metrics[100].to_s + ','  + origin_metrics[:duplicates].to_s +  ','  + origin_metrics[:realduplicates].to_s + ',' + origin_metrics[:unsuccesful].to_s + ',' + origin_metrics[:sent].to_s + ',' + origin_metrics[:other_length].to_s  + ',' + origin_metrics[:hop_counts].to_s  + ',' + origin_metrics[:hop_counts0].to_s  + ',' + origin_metrics[:hop_counts100].to_s + "\n")

  end


  r.write "\nSummary\n--------------------\n"
  r.write "\nTotal Yield is #{total_metrics[:arrived].to_f/total_metrics[:sent]}\n"
  r.write "Duplicate rate is #{total_metrics[:duplicates].to_f/total_metrics[:sent]}\n"   
  r.write "Real Duplicate rate is #{total_metrics[:real_duplicates].to_f/total_metrics[:sent]}\n"        
  r.write "To sink 0, #{total_metrics[0].to_f/total_metrics[:arrived]} were sent, to 100 #{total_metrics[100].to_f/total_metrics[:arrived]}\n"        
  csvfile.close
  r.close 
  pathfile.close
end
